﻿using System;
using System.Linq.Expressions;
using System.Reflection;

namespace Lr
{
    /// <summary>
    /// Helper class for retrieving <see cref="PropertyInfo"/> objects.
    /// </summary>
    public static class PropertyInfoHelper
    {
        /// <summary>
        /// Returns a <see cref="PropertyInfo"/> object based on a selection.
        /// </summary>
        /// <typeparam name="TObject">The type of the object where the property lives in.</typeparam>
        /// <typeparam name="TProperty">The type of the property.</typeparam>
        /// <param name="propertySelector">The expression (type-safe) to select the property.</param>
        /// <returns>The <see cref="PropertyInfo"/> object for the selected property.</returns>
        public static PropertyInfo GetPropertyInfo<TObject, TProperty>(Expression<Func<TObject, TProperty>> propertySelector)
        {
            ThrowIf.Null(() => propertySelector);

            var objectType = typeof(TObject);
            var propertyType = typeof(TProperty);

            var memberExpression = propertySelector.Body as MemberExpression;
            if (memberExpression == null) {
                throw new ArgumentNullException(
                        "Expression '{0}' refers to a method, not a property.".FormatWith(
                            propertySelector.ToStringSafe()
                        )
                    );
            }

            var propertyInfo = memberExpression.Member as PropertyInfo;
            if (propertyInfo == null) {
                throw new ArgumentException(
                        "Expression '{0}' refers to a field, not a property.".FormatWith(
                            propertySelector.ToStringSafe()
                        )
                    );
            }

            return propertyInfo;
        }
    }
}
